{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions in Python are reusable blocks of code that perform a specific task. They allow you to break down your program into smaller, more manageable pieces, making it easier to read, debug, and maintain your code.\n",
    "\n",
    "To use a function in Python, you need to define the function first and then \"call\" it when you want to use it. When you call a function, you pass in any necessary input parameters, and the function returns a result (if any). In addition, functions can have optional arguments and default values, which provide flexibility and make them more versatile.\n",
    "\n",
    "Python has many built-in functions like print(), len(), max(), min(), etc. You can also create your own custom functions using the def keyword.\n",
    "\n",
    "Here's an example of a simple function that takes two arguments and returns their sum:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_numbers(x, y):\n",
    "    return x + y\n",
    "\n",
    "# Call the function\n",
    "result = add_numbers(2, 3)\n",
    "print(result)   # Output: 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, we define a function called add_numbers() that takes two input parameters (x and y). The function performs the addition operation on these two inputs and returns the result using the return statement. We then call the function and pass in the arguments 2 and 3, and store the result in a variable called result. Finally, we print out the value of result.\n",
    "\n",
    "Functions are essential building blocks in programming, and mastering their use is vital for writing efficient and maintainable code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实例\n",
    "def hello():\n",
    "    print(\"Hello World!\")\n",
    "    # return 不是必须的，如果不需要返回数据，可以不用return\n",
    "\n",
    "def my_abs(x):\n",
    "    if x >= 0:\n",
    "        return x  # 返回给调用函数的一方\n",
    "    else:\n",
    "        return -x  # 返回给调用函数的一方   思考：这是在求什么？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# how to use??\n",
    "def hello():\n",
    "    print(\"Hello World!\")\n",
    "\n",
    "hello()\n",
    "\n",
    "my_abs(-6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 练习1\n",
    "\n",
    "写一个函数，打印五次【我是最厉害的！】"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print5time():\n",
    "    ???   \n",
    "       ???"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print5time()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 练习2\n",
    "\n",
    "写一个函数，打印五次你的座右铭"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print5time_2(words):# 接受words变量\n",
    "    ???\n",
    "       ???\n",
    "      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_words = input(\"输入你的座右铭：\") \n",
    "print(\"=========结果如下========\")\n",
    "print5time_2(my_words)  #传参（）内容变量自定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 参数传递\n",
    "\n",
    "可更改(mutable)与不可更改(immutable)对象\n",
    "在 python 中，strings, tuples, 和 numbers 是不可更改的对象，而 list,dict 等则是可以修改的对象。\n",
    "\n",
    "不可变类型：变量赋值 a=5 后再赋值 a=10，这里实际是新生成一个 int 值对象 10，再让 a 指向它，而 5 被丢弃，不是改变a的值，相当于新生成了a。\n",
    "\n",
    "可变类型：变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改，本身la没有动，只是其内部的一部分值被修改了。\n",
    "\n",
    "python 函数的参数传递：\n",
    "\n",
    "不可变类型：如 整数、字符串、元组。如fun（a），传递的只是a的值，没有影响a对象本身。比如在 fun（a）内部修改 a 的值，只是修改另一个复制的对象，不会影响 a 本身。\n",
    "\n",
    "可变类型：如 列表，字典。如 fun（la），则是将 la 真正的传过去，修改后fun外部的la也会受影响\n",
    "\n",
    "python 中一切都是对象，严格意义我们不能说值传递还是引用传递，我们应该说传不可变对象和传可变对象\n",
    "\n",
    "## English\n",
    "\n",
    "Parameter transfer\n",
    "\n",
    "Mutable and immutable objects In Python, strings, tuples, and numbers are immutable objects, while lists, dicts, and others are modifiable objects.\n",
    "\n",
    "\n",
    "\n",
    "Invariant type: The variable is assigned a value of a=5 and then a value of a=10. In this case, a new int value object 10 is generated, and a points to it, while 5 is discarded. Instead of changing the value of a, it is equivalent to a new generation of a.\n",
    "\n",
    "\n",
    "\n",
    "Variable type: Assigning la=[1,2,3,4] to a variable and then assigning la [2]=5 changes the value of the third element of the list la. La itself has not changed, but only a portion of its internal values have been modified.\n",
    "\n",
    "\n",
    "\n",
    "Parameter passing for Python functions:\n",
    "\n",
    "\n",
    "\n",
    "Immutable types: such as integers, strings, tuples. As in fun (a), only the value of a is passed, without affecting the object itself. For example, modifying the value of a within fun (a) only modifies another replicated object without affecting the value of a.\n",
    "\n",
    "\n",
    "\n",
    "Variable types: such as lists, dictionaries. If Fun (la) is used, it means that the real la is passed over, and the modified la outside Fun will also be affected\n",
    "\n",
    "\n",
    "\n",
    "Everything in Python is an object, strictly speaking, we cannot say whether it is value passing or reference passing. Instead, we should say passing immutable objects and passing mutable objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# immutable\n",
    "def ChangeInt(a):\n",
    "    print('In function', a)\n",
    "    a = 10\n",
    "    print('Has changed', a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "In function 2\n",
      "Has changed 10\n",
      "Out function 2\n"
     ]
    }
   ],
   "source": [
    "a = 2\n",
    "ChangeInt(a)\n",
    "print('Out function', a) # 结果是 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Mutable\n",
    "def changeme(mylist):\n",
    "    # \"修改传入的列表\"\n",
    "    print('in function', mylist)\n",
    "    mylist.append(40)\n",
    "    print(\"after change value in function: \", mylist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "in function [10, 20, 30]\n",
      "after change value in function:  [10, 20, 30, 40]\n",
      "out function:  [10, 20, 30, 40]\n"
     ]
    }
   ],
   "source": [
    "# 调用changeme函数\n",
    "mylist = [10,20,30]\n",
    "changeme(mylist)\n",
    "print(\"out function: \", mylist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 参数\n",
    "以下是调用函数时可使用的正式参数类型：\n",
    "\n",
    "1. 必备参数  -- 以上都是必备参数\n",
    "2. 关键字参数\n",
    "3. 默认参数\n",
    "4. 不定长参数\n",
    "\n",
    "parameter\n",
    "\n",
    "The following are the formal parameter types that can be used when calling functions:\n",
    "\n",
    "\n",
    "\n",
    "1. Mandatory parameters - all of the above are mandatory parameters\n",
    "\n",
    "2. Keyword parameters\n",
    "\n",
    "3. Default parameters\n",
    "\n",
    "4. Indefinite length parameter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 关键字参数\n",
    "关键字参数和函数调用关系紧密，函数调用使用关键字参数来确定传入的参数值。\n",
    "\n",
    "使用关键字参数允许函数调用时参数的顺序与声明时不一致，因为 Python 解释器能够用参数名匹配参数值。\n",
    "\n",
    "Keyword parameters are closely related to function calls, and function calls use keyword parameters to determine the incoming parameter values.\n",
    "\n",
    "The use of keyword parameters allows the order of parameters during function calls to be inconsistent with the declaration, as the Python interpreter can match parameter values with parameter names."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "#函数说明\n",
    "def printinfo( name, age ):\n",
    "    # \"打印任何传入的字符串\"\n",
    "    print(\"Name: \", name)\n",
    "    print(\"Age \", age)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name:  Tom\n",
      "Age  44\n",
      "Name:  miki\n",
      "Age  50\n"
     ]
    }
   ],
   "source": [
    "# 必备参数,一定要按顺序name,age来填写，不能乱\n",
    "printinfo(\"Tom\", 44)\n",
    "# 调用printinfo函数--关键字参数，就可以不按顺序。\n",
    "printinfo(age=50, name=\"miki\")  #name是变量，miki是字符串"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 缺省参数\n",
    "调用函数时，缺省参数的值如果没有传入，则被认为是默认值。下例会打印默认的age，如果age没有被传入：\n",
    "\n",
    "Default parameters\n",
    "\n",
    "When calling a function, if the value of the default parameter is not passed in, it is considered the default value. The following example will print the default age, if the age has not been passed in"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "#可写函数说明\n",
    "def printinfo2( name, age = 35 ):\n",
    "    # \"打印任何传入的字符串\"\n",
    "    print(\"Name: \", name)\n",
    "    print(\"Age \", age)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name:  Mery\n",
      "Age  35\n",
      "Name:  Mery\n",
      "Age  30\n"
     ]
    }
   ],
   "source": [
    "# 缺省参数\n",
    "printinfo2(\"Mery\") # age默认值就是35 \n",
    "printinfo2(\"Mery\",30) # age默认值就是35 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "printinfo2(\"Mery\",30,30)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 不定长参数\n",
    "\n",
    "你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数，和上述2种参数不同，声明时不会命名。基本语法如下：\n",
    "\n",
    "Indefinite length parameter\n",
    "\n",
    "You may need a function that can handle more parameters than when it was originally declared. These parameters are called indefinite length parameters, and unlike the two aforementioned parameters, they are not named when declared. The basic syntax is as follows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 函数说明\n",
    "def printinfo3(arg1, *vartuple ):  #\"*\"后面内容自定义\n",
    "    print(\"arg1:\", arg1)\n",
    "    for var in vartuple:\n",
    "        print(\"不定长参数\", var)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-------------------\n",
      "arg1: 70\n",
      "不定长参数 60\n",
      "不定长参数 50\n"
     ]
    }
   ],
   "source": [
    "# 调用printinfo 函数\n",
    "# printinfo3(10)\n",
    "print('-------------------')\n",
    "printinfo3(70, 60, 50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "arg1: 70\n",
      "不定长参数 60\n",
      "不定长参数 50\n",
      "不定长参数 3\n",
      "不定长参数 4\n",
      "不定长参数 5\n"
     ]
    }
   ],
   "source": [
    "printinfo3(70, 60, 50,3,4,5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### return 语句\n",
    "return语句[表达式]退出函数，选择性地向调用方返回一个表达式。不带参数值的return语句返回None。之前的例子都没有示范如何返回数值，下例便告诉你怎么做："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 函数说明\n",
    "def my_sum( arg1, arg2 ):\n",
    "    # 返回2个参数的和.\"\n",
    "    total = arg1 + arg2\n",
    "    print(\"函数内求得值 : \", total)\n",
    "    return total"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# my_sum函数\n",
    "total = my_sum(10,20)\n",
    "print(total)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_sum( arg1, arg2 ):\n",
    "    total = arg1 + arg2\n",
    "    \n",
    "    print(\"函数内求得值 : \", total) #因为函数变量total作用域是内部，需要通过return返回到函数外面\n",
    "    return total\n",
    "    # 如果没有return，total值在外面是拿不到"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "total = my_sum(5,6)\n",
    "print(total)  # None 就是没有东西返回"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 练习3 \n",
    "\n",
    "冰雹猜想验证，所有正整数如果是偶数就除以2，如果是奇数就乘以3倍加1，最后所有整数都会回到1。\n",
    "\n",
    "如果n是偶数：\n",
    "\n",
    "  n = n / 2\n",
    "  \n",
    "如果n是奇数：\n",
    "\n",
    "  n = n*3 +1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def collatz_sequence(n):\n",
    "    \"\"\"\n",
    "    冰雹猜想：记录数值变化的过程（函数说明）\n",
    "    \n",
    "    \"\"\"  \n",
    "    sequence = [n]\n",
    "    while n ?? 1:   # 猜想结果是，所有正整数都会回到1\n",
    "        \n",
    "        if n ？ 2 == 0:  # 如果是偶数 N/2,求余数\n",
    "            ？？？\n",
    "        else: # 如果是奇数 3N+1\n",
    "            ？？？\n",
    "        \n",
    "        sequence.append(n)\n",
    "    ？？？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "your_number = int(input(\"输入一个正整数\"))\n",
    "result = collatz_sequence(your_number)\n",
    "print(\"{}的变化是{}\".format(your_number, result))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "8//2 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "8/2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 变量作用域\n",
    "Python 中，程序的变量并不是在哪个位置都可以访问的，访问权限决定于这个变量是在哪里赋值的。\n",
    "\n",
    "变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种，分别是：\n",
    "\n",
    "1. L （Local） 局部作用域\n",
    "2. E （Enclosing） 闭包函数外的函数中\n",
    "3. G （Global） 全局作用域\n",
    "4. B （Built-in） 内建作用域\n",
    "\n",
    "以 L –> E –> G –>B 的规则查找，即：在局部找不到，便会去局部外的局部找（例如闭包），再找不到就会去全局找，再者去内建中找。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### L(Local)局部变量\n",
    "\n",
    "包含在def关键字定义的语句块中，即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归，即自己调用自己，每次调用都会创建一个新的局部命名空间。在函数内部的变量声明，除非特别的声明为全局变量，否则均默认为局部变量。有些情况需要在函数内部定义全局变量，这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈，仅仅是暂时的存在，依赖创建该局部作用域的函数是否处于活动的状态。所以，一般建议尽量少定义全局变量，因为全局变量在模块文件运行的过程中会一直存在，占用内存空间。\n",
    "\n",
    "#### E(enclosing)闭包函数外的函数中\n",
    "\n",
    "E也包含在def关键字中，E和L是相对的，E相对于更上层的函数而言也是L。与L的区别在于，对一个函数而言，L是定义在此函数内部的局部作用域，而E是定义在此函数的上一层父级函数的局部作用域。主要是为了实现Python的闭包，而增加的实现。\n",
    "\n",
    "#### G(global)全局作用域\n",
    "\n",
    "即在模块层次中定义的变量，每一个模块都是一个全局作用域。也就是说，在模块文件顶层声明的变量具有全局作用域，从外部开来，模块的全局变量就是一个模块对象的属性。\n",
    "注意：全局作用域的作用范围仅限于单个模块文件内\n",
    "\n",
    "#### B(built-in)内建作用域\n",
    "系统内固定模块里定义的变量，如预定义在builtin 模块内的变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = 2.9\n",
    "int(n)  # 内建作用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "outer 函数里面 1\n",
      "inner 函数里面 2\n",
      "运行inner函数之后 1\n",
      "全局 0\n"
     ]
    }
   ],
   "source": [
    "count = 0  # 全局作用域\n",
    "\n",
    "def outer():\n",
    "    count = 1  # 闭包函数外的函数中\n",
    "    print('outer 函数里面', count)\n",
    "    \n",
    "    def inner():\n",
    "        count = 2  # 局部作用域\n",
    "        print('inner 函数里面', count)\n",
    "    \n",
    "    inner()\n",
    "    print('运行inner函数之后', count)\n",
    "\n",
    "outer()\n",
    "print('全局', count)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python 中只有模块（module），类（class）以及函数（def、lambda）才会引入新的作用域，其它的代码块（如 if/elif/else/、try/except、for/while等）是不会引入新的作用域的，也就是说这些语句内定义的变量，外部也可以访问，如下代码：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if True:\n",
    "    a = 0\n",
    "\n",
    "# 虽然没有定义a，但还是能访问,if 不是函数，所以会影响外面\n",
    "\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "函数内的b 5\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'bbbb' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-798fa5959d23>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mfun_b\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbbbb\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# name 'bbbb' is not defined  外面没有定义b，所以b就没有定义\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m: name 'bbbb' is not defined"
     ]
    }
   ],
   "source": [
    "def fun_b():\n",
    "    bbbb = 5\n",
    "    print(\"函数内的b\",bbbb)\n",
    "\n",
    "fun_b()\n",
    "print(bbbb)  # name 'bbbb' is not defined  外面没有定义b，所以b就没有定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### global \n",
    "当内部作用域想修改外部作用域的变量时，就要用到global关键字了。\n",
    "\n",
    "以下实例修改全局变量 num："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fun1函数里面 1\n",
      "fun1里面，修改值之后 123\n",
      "运行函数后 123\n"
     ]
    }
   ],
   "source": [
    "num = 1\n",
    "def fun1():\n",
    "    global num  # 需要使用 global 关键字声明\n",
    "    print('fun1函数里面', num) \n",
    "    num = 123\n",
    "    print('fun1里面，修改值之后',num)\n",
    "fun1()\n",
    "print(u'运行函数后',num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "UnboundLocalError",
     "evalue": "local variable 'a' referenced before assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mUnboundLocalError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-21-fa25d69ebb8e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mtest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# UnboundLocalError: local variable 'a' referenced before assignment， 程序报错，a变量没有定义\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-21-fa25d69ebb8e>\u001b[0m in \u001b[0;36mtest\u001b[0;34m()\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mtest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m     \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      6\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0mtest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# UnboundLocalError: local variable 'a' referenced before assignment， 程序报错，a变量没有定义\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'a' referenced before assignment"
     ]
    }
   ],
   "source": [
    "# 错误示范\n",
    "a = 10\n",
    "\n",
    "def test():\n",
    "    a = a + 1\n",
    "    print(a)\n",
    "test() # UnboundLocalError: local variable 'a' referenced before assignment， 程序报错，a变量没有定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11\n"
     ]
    }
   ],
   "source": [
    "# 推荐做法，传入参数\n",
    "a = 10\n",
    "\n",
    "def test(var_a):\n",
    "    var_a = var_a + 1\n",
    "    print(var_a)\n",
    "\n",
    "test(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11\n"
     ]
    }
   ],
   "source": [
    "# 不推荐做法  原因：和外面的混在一起\n",
    "a = 10\n",
    "def test():\n",
    "    global a\n",
    "    a = a + 1\n",
    "    print(a)\n",
    "test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 练习"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 请定义一个 square_of_sum 函数，它接受一个list，返回list中每个元素平方的和\n",
    "\n",
    "def square_of_sum(my_list):\n",
    "    total = 0 # 总和\n",
    "    \n",
    "    for item in my_list:\n",
    "        print(\"{}的平方是{}\".format(item, item**2)) #字符串格式化输出\n",
    "        ???\n",
    "        #print(total)\n",
    "        \n",
    "  # 返回结果\n",
    "    ???\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(square_of_sum([1, 2, 3, 4, 5]))\n",
    "print(square_of_sum([-5, 0, 5, 15, 25]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sum([1,2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = [7,1,2,3]\n",
    "l.sort()\n",
    "l"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 请定义一个 greet() 函数，它包含一个默认参数，\n",
    "# 如果没有传入，打印 'Hello, world.'，如果传入，打印 'Hello, xxx.'\n",
    "\n",
    "def greet(input_string='world'):\n",
    "    print(???)\n",
    "\n",
    "greet()\n",
    "greet(???)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "传参数顺序：首先定义一般参数，然后定义缺省值参数，最后定义不定长参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 扩展知识- 函数式编程\n",
    "\n",
    "#### 传入函数\n",
    "既然变量可以指向函数，函数的参数能接收变量，那么一个函数就可以接收另一个函数作为参数，这种函数就称之为高阶函数。\n",
    "\n",
    "一个最简单的高阶函数：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add(x, y, f):\n",
    "    return f(x) + f(y)\n",
    "\n",
    "print(add(-5, 6, abs)) # abs本身是一个函数，就是求绝对值的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "abs(-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Map 函数\n",
    "\n",
    "map()函数接收两个参数，一个是函数，一个是列表，map将传入的函数依次作用到序列的每个元素，并把结果作为新的列表返回\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    return x * x\n",
    "\n",
    "r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])\n",
    "print('python2 和 python3 有些不同，在3里面，r是一个迭代器', r)\n",
    "# 这是错误的，print(r[0])，迭代器没有序号，不是队列，每次使用next函数只会返回一个值\n",
    "# print(next(r)) 可以获取下一个值\n",
    "# list(r) # 这样可以把迭代器转换成队列\n",
    "\n",
    "# for循环可以自动判断迭代器的结束，可以用for来遍历\n",
    "for i in r:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 同等效果\n",
    "def f(x):\n",
    "    return x * x\n",
    "\n",
    "L = []\n",
    "for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:\n",
    "    L.append(f(n))\n",
    "print(L)\n",
    "\n",
    "for i in L:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### filter\n",
    "和map()类似，filter()也接收一个函数和一个序列。和map()不同的是，filter()把传入的函数依次作用于每个元素，然后根据返回值是True还是False决定保留还是丢弃该元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_odd(n):\n",
    "    return n % 2 == 1\n",
    "\n",
    "list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Reduce "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "reduce把一个函数作用在一个序列[x1, x2, x3, ...]上，这个函数必须接收两个参数，reduce把结果继续和序列的下一个元素做求和计算，其效果就是："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce  # python2 不需要\n",
    "\n",
    "def fn(x, y):\n",
    "    return x + y   #x代表上一次运算结果，y代表下一个数\n",
    "\n",
    "print(reduce(fn, [1, 3, 5, 7, 9]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 匿名函数\n",
    "\n",
    "当我们在传入函数时，有些时候，不需要显式地定义函数，直接传入匿名函数更方便。\n",
    "\n",
    "关键字lambda表示匿名函数，冒号前面的x表示函数参数。\n",
    "\n",
    "匿名函数有个限制，就是只能有一个表达式，不用写return，返回值就是该表达式的结果。\n",
    "\n",
    "用匿名函数有个好处，因为函数没有名字，不必担心函数名冲突。此外，匿名函数也是一个函数对象，也可以把匿名函数赋值给一个变量，再利用变量来调用该函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 例子\n",
    "list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 相同功能\n",
    "def f(x):\n",
    "    return x * x\n",
    "\n",
    "list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
